﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinAlg3D
{
    /// <summary>
    /// Describes and manipulates a vector in four-dimensional (4-D) space.
    /// </summary>
    [Serializable()]
    public struct Vector4
    {
        private float x, y, z, w;

        /// <summary>
        /// Initializes a new instance of the Vector4 struct.
        /// </summary>
        /// <param name="x">x component of the vector.</param>
        /// <param name="y">y component of the vector.</param>
        /// <param name="z">z component of the vector.</param>
        /// <param name="w">w component of the vector.</param>
        public Vector4(float x, float y, float z, float w)
        {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }

        // Properties

        /// <summary>
        /// Retrieves or sets the x component of a 4-D vector.
        /// </summary>
        public float X
        {
            get { return x; }
            set { x = value; }
        }

        /// <summary>
        /// Retrieves or sets the y component of a 4-D vector.
        /// </summary>
        public float Y
        {
            get { return y; }
            set { y = value; }
        }

        /// <summary>
        /// Retrieves or sets the z component of a 4-D vector.
        /// </summary>
        public float Z
        {
            get { return z; }
            set { z = value; }
        }

        /// <summary>
        /// Retrieves or sets the w component of a 4-D vector.
        /// </summary>
        public float W
        {
            get { return w; }
            set { w = value; }
        }

        #region Empty
        /// <summary>
        /// Retrieves an empty 4-D vector.
        /// </summary>
        public static Vector4 Empty
        {
            get
            {
                return new Vector4(0, 0, 0, 0);
            }
        }
        #endregion

        // Methods

        #region Addition

        /// <summary>
        /// Adds two 4-D vectors.
        /// </summary>
        /// <param name="vector"></param>
        public void Add(Vector4 vector)
        {
            this += vector;
        }

        /// <summary>
        /// Adds two 4-D vectors.
        /// </summary>
        /// <param name="vector1">Source Vector4f.</param>
        /// <param name="vector2">Source Vector4f.</param>
        /// <returns>Sum of the two Vector4f structures.</returns>
        public static Vector4 Add(Vector4 vector1, Vector4 vector2)
        {
            return new Vector4(vector1.x + vector2.x, vector1.y + vector2.y, vector1.z + vector2.z, vector1.w + vector2.w);
        }

        /// <summary>
        /// Adds two 4-D vectors.
        /// </summary>
        /// <param name="vector1"></param>
        /// <param name="vector2"></param>
        /// <returns></returns>
        public static Vector4 operator +(Vector4 vector1, Vector4 vector2)
        {
            return new Vector4(vector1.x + vector2.x, vector1.y + vector2.y, vector1.z + vector2.z, vector1.w + vector2.w);
        }

        #endregion

        #region DotProduct
        /// <summary>
        /// Determines the dot product of two 4-D vectors.
        /// </summary>
        /// <param name="vector1">Source Vector4 structure.</param>
        /// <param name="vector2">Source Vector4 structure.</param>
        /// <returns>A Single value that is the dot product.</returns>
        public static float Dot(Vector4 vector1, Vector4 vector2)
        {
            return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z + vector1.w * vector2.w;
        }
        #endregion

        #region CrossProduct
        #endregion

        #region Equals
        /// <summary>
        /// Returns a value that indicates whether the current instance is equal to a specified object.
        /// </summary>
        /// <param name="obj">Object with which to make the comparison.</param>
        /// <returns>Value that is true if the current instance is equal to the specified object, or false if it is not.</returns>
        public override bool Equals(object obj)
        {
            // If parameter is null return false.
            if (obj == null)
            {
                return false;
            }

            // If parameter cannot be cast to Vector4f return false.
            if (!(obj is Vector4))
            {
                return false;
            }

            // Return true if the fields match:
            return (x == ((Vector4)obj).x && y == ((Vector4)obj).y && z == ((Vector4)obj).z && w == ((Vector4)obj).w);
        }
        #endregion

        #region GetHashCode
        /// <summary>
        /// Returns the hash code for the current instance.
        /// </summary>
        /// <returns>Hash code for the instance.</returns>
        public override int GetHashCode()
        {
            return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
        }
        #endregion

        #region Length
        /// <summary>
        /// Returns the length of a 4-D vector.
        /// </summary>
        /// <param name="vector">Source Vector4f structure.</param>
        /// <returns>A Single value that contains the vector's length.</returns>
        public static float Length(Vector4 vector)
        {
            return vector.Length();
        }

        /// <summary>
        /// Returns the length of a 4-D vector.
        /// </summary>
        /// <returns>A Single value that contains the vector's length.</returns>
        public float Length()
        {
            return (float)System.Math.Sqrt(x * x + y * y + z * z + w * w);
        }
        #endregion

        #region LengthSquared
        /// <summary>
        /// Returns the square of the length of a 4-D vector.
        /// </summary>
        /// <param name="vector">Source Vector4f structure.</param>
        /// <returns>A Single value that contains the vector's squared length.</returns>
        public static float LengthSquared(Vector4 vector)
        {
            return vector.LengthSquared();
        }


        /// <summary>
        /// Returns the square of the length of a 4-D vector.
        /// </summary>
        /// <returns>A Single value that contains the vector's squared length.</returns>
        public float LengthSquared()
        {
            return x * x + y * y + z * z + w * w;
        }
        #endregion

        #region Multiply
        /// <summary>
        /// Determines the dot product of two 4-D vectors.
        /// </summary>
        /// <param name="vector1">Source Vector4 structure.</param>
        /// <param name="vector2">Source Vector4 structure.</param>
        /// <returns>A Single value that is the dot product.</returns>
        public static float Multiply(Vector4 vector1, Vector4 vector2)
        {
            return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z + vector1.w * vector2.w;
        }
        #endregion

        #region ToArray
        /// <summary>
        /// Returns a float array with four components: array[0] = x, array[1] = y, array[2] = z
        /// </summary>
        /// <returns></returns>
        public float[] toArray()
        {
            float[] array = new float[4];
            array[0] = x;
            array[1] = y;
            array[2] = z;
            array[3] = w;
            return array;
        }
        #endregion

        #region ToString
        public override string ToString()
        {
            return "x: " + x.ToString() + " y: " + y.ToString() + " z: " + z.ToString() + " w: " + w.ToString();
        }
        #endregion

        // Operators

        #region op_Equality
        /// <summary>
        /// Compares the current instance of a class to another instance to determine whether they are the same.
        /// </summary>
        /// <param name="vector1">The Vector4 structure to the left of the equality operator.</param>
        /// <param name="vector2">The Vector4 structure to the right of the equality operator.</param>
        /// <returns></returns>
        public static bool operator ==(Vector4 left, Vector4 right)
        {
            return (left.x == right.x && left.y == right.y && left.z == right.z && left.w == right.w);
        }
        #endregion

        #region op_Inequality
        /// <summary>
        /// Compares the current instance of a class to another instance to determine whether they are different.
        /// </summary>
        /// <param name="left">The Vector4 structure to the left of the inequality operator.</param>
        /// <param name="right">The Vector4 structure to the right of the inequality operator.</param>
        /// <returns></returns>
        public static bool operator !=(Vector4 left, Vector4 right)
        {
            return !(left.x == right.x && left.y == right.y && left.z == right.z && left.w == right.w);
        }
        #endregion

        #region op_Multiply
        /// <summary>
        /// Determines the dot product of two 4-D vectors.
        /// </summary>
        /// <param name="vector1">Source Vector4f structure.</param>
        /// <param name="vector2">Source Vector4f structure.</param>
        /// <returns>A Single value that is the dot product.</returns>
        public static float operator *(Vector4 vector1, Vector4 vector2)
        {
            return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z + vector1.w * vector2.w;
        }
        #endregion

    }
}
